Introdução ao Numpy

master:tutorial_numpy_1_index Tutorial Numpy - index

Copiando variáveis ndarray

Índice:

O ndarray foi projetado para acesso otimizado a uma grande quantidade de dados. Neste sentido, os conceitos descritos a seguir sobre as três formas de cópias entre variáveis ditas sem cópia, cópia rasa (shallow) e cópia profunda (deep) são fundamentais para uma codificação eficiente. Podemos dizer que um ndarray possui o cabeçalho que contém dados pelas informações sobre o tipo do elemento, a dimensionalidade (shape) e passo ou deslocamento para o próximo elemento (strides) e os dados raster em si. A tabela a seguir mostra a situação do cabeçalho e dos dados nos três tipos de cópias.

Tipo Cabeçalho: Type, Shape, Strides Dados raster Exemplo
Sem cópia, apenas ref apontador original apontador original a = b
Cópia rasa novo apontador original b = a.reshape, slicing, a.T
Cópia profunda novo novo a = b.copy()

Sem cópia explícita, apenas referência

No caso abaixo, usaremos o comando normal de igual como atribuição do array a para o array b. Verifica-se que tanto o shape como os dados de b são os mesmos de a. Tudo se passa como b fosse apenas um apontador para a. Qualquer modificação em b é refletida em a.


In [1]:
import numpy as np

a = np.arange(6) 
b = a
print "a =\n",a
print "b =\n",b
b.shape = (2,3)                           # mudança no shape de b,
print "\na shape =",a.shape               # altera o shape de a

b[0,0] = -1                               # mudança no conteúdo de b
print "a =\n",a                             # altera o conteudo de a  

print "\nid de a = ",id(a)                # id é um identificador único de objeto
print "id de b = ",id(b)                  # a e b possuem o mesmo id

print 'np.may_share_memory(a,b):',np.may_share_memory(a,b)


a =
[0 1 2 3 4 5]
b =
[0 1 2 3 4 5]

a shape = (2, 3)
a =
[[-1  1  2]
 [ 3  4  5]]

id de a =  140638036202160
id de b =  140638036202160
np.may_share_memory(a,b): True

Observe que mesmo no retorno de uma função, a cópia explícita pode não acontecer. Veja o exemplo a seguir de uma função que apenas retorna a variável de entrada:


In [2]:
def cc(a):
  return a
b = cc(a)
print "id de a = ",id(a)
print "id de b = ",id(b)
print 'np.may_share_memory(a,b):',np.may_share_memory(a,b)


id de a =  140638036202160
id de b =  140638036202160
np.may_share_memory(a,b): True

Cópia rasa

A cópia rasa é muito útil e extensivamente utilizada. É usada quando se quer indexar o array original através da mudança de dimensionalidade ou do refatiamento, porém sem a necessidade de realizar uma cópia dos dados raster. Desta forma consegue-se uma otimização no acesso ao array n-dimensional. Existem várias formas onde a cópia rasa acontece, sendo as principais:

  1. no caso do reshape onde o número de elementos do ndarray é o mesmo, porém sua dimensionalidade é alterada;
  2. no caso de fatiamento onde um subarray é indexado;
  3. no caso de transposição do array;
  4. no caso de linearização do raster através do ravel(). entre outros.

Reshape

O exemplo a seguir mostra inicialmente a criação de um vetor unidimensional sequencial sendo "visto" de forma bidimensional ou tridimensional.


In [3]:
a = np.arange(30)
print "a =\n", a
b = a.reshape( (5, 6))
print "b =\n", b
b[:, 0] = -1
print "a =\n", a
c = a.reshape( (2, 3, 5) )
print "c =\n", c
print 'c.base is a:',c.base is a
print 'np.may_share_memory(a,c):',np.may_share_memory(a,c)


a =
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 25 26 27 28 29]
b =
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]
 [24 25 26 27 28 29]]
a =
[-1  1  2  3  4  5 -1  7  8  9 10 11 -1 13 14 15 16 17 -1 19 20 21 22 23 -1
 25 26 27 28 29]
c =
[[[-1  1  2  3  4]
  [ 5 -1  7  8  9]
  [10 11 -1 13 14]]

 [[15 16 17 -1 19]
  [20 21 22 23 -1]
  [25 26 27 28 29]]]
c.base is a: True
np.may_share_memory(a,c): True

Slice - Fatiamento

O exemplo a seguir mostra a cópia rasa no uso de fatiamento. No exemplo, todos os elementos de linhas e colunas pares são modificados para 1. CUIDADO: quando é feita a atribuição de b = 1., é importante que b seja referenciado como ndarray na forma b[:,:], caso contrário, se fizermos b = 1., uma nova variável é criada.


In [4]:
import ia636 as ia

a = np.zeros( (5, 6))
print ia.iaimginfo(a)
b = a[::2,::2]
print ia.iaimginfo(b)
b[:,:] = 1.
print 'b=\n', b 
print 'a=\n', a 
print 'b.base is a:',b.base is a
print 'np.may_share_memory(a,b):',np.may_share_memory(a,b)


---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-4-fd1a7c1f0e54> in <module>()
----> 1 import ia636 as ia
      2 
      3 a = np.zeros( (5, 6))
      4 print ia.iaimginfo(a)
      5 b = a[::2,::2]

ImportError: No module named ia636

In [ ]:
Este outro exemplo é uma forma atraente de processar uma coluna de uma matriz bidimensional,
porém é preciso CUIDADO, pois o uso de b deve ser com b[:] se for atribuído um novo valor para
ele, caso contrário, se fizermos b = arange(5), uma nova variável é criada.

.. code:: python

    a = np.arange(25).reshape((5,5))
    print 'a=\n',a
    b = a[:,0]
    print 'b=',b
    b[:] = np.arange(5)
    print 'b=',b
    print 'a=\n',a 

Transposto
----------

A operação matricial de transposição que troca linhas por colunas produz também um *view* 
da imagem, sem necessidade de cópia:

.. code:: python

    a = np.arange(24).reshape((4,6))
    print 'a:\n',a
    at = a.T
    print 'at:\n',at
    print 'np.may_share_memory(a,at):',np.may_share_memory(a,at)
    
Ravel
-----

Aplicando-se o método ``ravel()`` a um ``ndarray``, gera-se um *view* do raster
linearizado (i.e. uma única dimensão) do ``ndarray``.

.. code:: python

    a = np.arange(24).reshape((4,6))
    print 'a:\n',a
    av = a.ravel()
    print 'av.shape:',av.shape
    print 'av:\n',av
    print 'np.may_share_memory(a,av):',np.may_share_memory(a,av)
    
Cópia profunda
==============

Cria uma copia completa do array, do seu shape e conteúdo. A recomendação é utilizar a 
função ``copy()`` para realizar a copia profunda, entretanto é possível conseguir a
copia profunda pelo ``np.array``.
    
.. code:: python

    b = a.copy()
    c = np.array(a, copy=True)
    
    print "id de a = ",id(a)
    print "id de b = ",id(b)
    print "id de c = ",id(c)


Documentação Oficial Numpy
===========================

`http://wiki.scipy.org/Tentative_NumPy_Tutorial#head-1529ae93dd5d431ffe3a1001a4ab1a394e70a5f2 Copies and Views`